#include <cstring>
#include <string>
#include <stdexcept>
#include <nlohmann/json.hpp>
#include <sw/redis++/redis++.h>
#include "../common/httplib.h"
#include "mysqlconn.hpp"
#include "../common/util.hpp"
using namespace std;
using json = nlohmann::json;

inline bool FindInRedis(const char* username, const char* password)
{
    // 可能会需要Docker进行部署，所以更新一个带Docker的解决方式
    const char* redisenv = getenv("REDIS_NAME");
    string redisconn = "tcp://";
    if(redisenv == nullptr)
        redisconn = redisconn + "127.0.0.1" + ":6379";
    else   
        redisconn = redisconn + redisenv + ":6379";
    sw::redis::Redis redis(redisconn);
    auto result = redis.hget("user:username:password", username);
    if(result)
        return result.value() == password;
    return false;
}

inline void AddToRedis_login(const string& username, const string& password)
{
    // 可能会需要Docker进行部署，所以更新一个带Docker的解决方式
    const char* redisenv = getenv("REDIS_NAME");
    string redisconn = "tcp://";
    if(redisenv == nullptr)
        redisconn = redisconn + "127.0.0.1" + ":6379";
    else   
        redisconn = redisconn + redisenv + ":6379";
    sw::redis::Redis redis(redisconn);
    redis.hset("user:username:password", username, password);
}

inline void AddSessionToRedis(const string& username, const string& sessionid)
{
    // 获取时间戳
    // 使用chrono获取当前时间点
    auto now = chrono::system_clock::now();
    // 转换为时间点自1970年以来的秒数（即Unix时间戳）
    auto duration = now.time_since_epoch();
    int64_t timestamp = chrono::duration_cast<chrono::seconds>(duration).count();

    // 现在要构造出sessiondata
    json j;
    j["username"] = username;
    j["lasttime"] = timestamp;
    string sessiondata = j.dump();

    // 然后把这些数据都加到Redis当中
    // 可能会需要Docker进行部署，所以更新一个带Docker的解决方式
    const char* redisenv = getenv("REDIS_NAME");
    string redisconn = "tcp://";
    if(redisenv == nullptr)
        redisconn = redisconn + "127.0.0.1" + ":6379";
    else   
        redisconn = redisconn + redisenv + ":6379";
    sw::redis::Redis redis(redisconn);
    try
    {
        // 使用HSET命令将Session数据存入Redis，这里假定我们使用sessionid作为Hash的key，数据字段命名为"data"
        auto result = redis.hset("session:" + sessionid, "data", sessiondata);
        if (result) 
            cout << "Session data added to Redis successfully!" << endl;
        else 
            cerr << "Failed to add session data to Redis." << endl;
    } 
    catch (const sw::redis::Error &e)
    {
        cerr << "Redis error: " << e.what() << endl;
    }
}

// 验证用户名和密码是否正确
inline bool authenticate(const char *username, const char *password)
{
    // 读取配置文件
    const string jsonpath = "./conf/db_config.json";
    DataBaseConf::DatabaseConfig& config = DataBaseConf::getDatabaseConfig(jsonpath);

    // 进行数据库连接
    mysqlconn conn(config.host, config.username, config.password, config.dbName);
    string str1 = username;
    string str2 = password;
    // 先到Redis里面找，如果没有再到MySQL中找
    if(FindInRedis(username, password))
        return true;

    // 构造SQL查询语句
    string query = "SELECT COUNT(*) FROM users WHERE username = '" + string(username) + "' AND password = '" + string(password) + "';";

    // SELECT COUNT(*) FROM users WHERE username = 'testonline' AND password = 'testonline';

    MYSQL_RES *result = conn.executeSql(query);

    if (result == NULL)
    {
        fprintf(stderr, "Failed to get query, sql: %s\n", query.c_str());
        return false;
    }

    MYSQL_ROW row = mysql_fetch_row(result);
    int count = atoi(row[0]);

    mysql_free_result(result);

    // 如果查询结果为非零值，表示找到了匹配的用户名和密码记录，返回true；否则返回false
    if(count > 0)
    {
        AddToRedis_login(username, password);
        return true;
    }
    return false;
}

inline void handle_login(const httplib::Request &request, httplib::Response &response)
{
    // 检查请求方法是否为POST
    if (request.method != "POST")
    {
        response.status = 405; // Method Not Allowed
        response.body = "Only POST requests are allowed for login.";
        return;
    }

    // 检查Content-Type是否为application/json
    string contentType = request.get_header_value("Content-Type");
    if (contentType.find("application/json") == string::npos)
    {
        response.status = 415; // Unsupported Media Type
        response.body = "Login request must have a Content-Type of application/json.";
        return;
    }

    size_t contentLength = 0;
    // 获取请求正文长度
    if(request.has_header("Content-Length"))
        contentLength = stoi(request.get_header_value("Content-Length"));
    if (contentLength == 0)
    {
        response.status = 400; // Bad Request
        response.body = "Login request must have a non-empty JSON body.";
        return;
    }

    // 读取请求正文
    string requestBody(request.body, 0, contentLength);

    // 使用nlohmann/json库解析请求正文
    json j;
    try
    {
        j = json::parse(requestBody);
    }
    catch (const json::parse_error &e)
    {
        response.status = 400; // Bad Request
        response.body = "Invalid JSON in login request.";
        return;
    }

    // 提取账号和密码
    string username = j.value("username", "");
    string password = j.value("password", "");

    // 生成sessionID
    string sessionid = UUIDHelper::uuid();

    // 实现账号和密码验证逻辑
    bool isValid = authenticate(username.c_str(), password.c_str());

    if (isValid)
    {
        // 验证成功，把session信息加到Redis当中
        AddSessionToRedis(username, sessionid);
        // 账号和密码验证成功
        response.status = 200; // OK
        response.set_header("Content-Type", "application/json");
        response.set_header("Set-Cookie", "SessionID=" + sessionid);
        response.body = "{\"message\":\"Login successful\"}";
    }
    else
    {
        // 账号和密码验证失败
        response.status = 401; // Unauthorized
        response.set_header("Content-Type", "application/json");
        response.body = "{\"message\":\"Invalid username or password\"}";
    }
}